<?php
// 应用公共文件
use JetBrains\PhpStorm\ArrayShape;
use PhpOffice\PhpSpreadsheet\IOFactory;
use think\facade\Db;
use think\Response;
use app\common\Log;

/**
 * 返回成功
 * @param mixed $data
 * @param int $code
 * @param string $message
 * @param mixed $debug
 * @return Response
 */
function success(mixed $data = [], int $code = 0, string $message = '请求成功', mixed $debug = false): Response
{
    $response = [
        'code' => (string)$code,
        'data' => $data,
        'msg' => $message
    ];
    if ($debug) {
        $response['debug'] = $debug;
    }
    return json($response);
}

/**
 * 返回报错
 * @param mixed $data
 * @param int $code
 * @param string $message
 * @param mixed $debug
 * @return Response
 */
function error(mixed $data = [], int $code = 1, string $message = '请求失败', mixed $debug = false): Response
{
    $response = [
        'code' => (string)$code,
        'data' => $data,
        'msg' => $message
    ];
    if ($debug) {
        $response['debug'] = $debug;
    }
    return json($response);
}

/**
 * curl post请求
 * @param $url
 * @param $data
 * @return bool|array
 */
function sendPost($url, $data): mixed
{
    $ch = curl_init();

// 设置cURL选项
    curl_setopt($ch, CURLOPT_URL, $url); // 设置请求的URL
    curl_setopt($ch, CURLOPT_POST, true); // 设置请求方法为POST
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); // 设置POST数据
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 设置返回结果为字符串，而非直接输出
    $err = curl_errno($ch);
// 执行cURL请求
    $response = curl_exec($ch);
// 关闭cURL会话
    curl_close($ch);
    if ($err) {
        return false;
    } else {
        return $response;
    }
}

/**
 * curl get请求
 * @param $url
 * @param $params
 * @return mixed
 */
function sendGet($url, $params): mixed
{
    // 构建查询字符串
    $query = http_build_query($params);

// 将查询字符串添加到URL
    $fullUrl = $url . '?' . $query;
    // 初始化cURL会话
    $ch = curl_init();

// 设置cURL选项
    curl_setopt($ch, CURLOPT_URL, $fullUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $err = curl_errno($ch);
// 执行cURL会话并获取结果
    $result = curl_exec($ch);

// 关闭cURL会话
    curl_close($ch);
    if ($err) {
        return false;
    } else {
        return $result;
    }

}

/**
 * 生成用户登录密码
 * @param mixed $password
 * @return string
 */
function initPassword(mixed $password = '123456'): string
{
    return md5('cdfh_' . $password);
}

/**
 * 把日志写入数据库
 * @param $event
 * @param $id
 * @param int $tag
 * @param mixed $remark
 * @return void
 */
function writeLogToDb($event, $id, int $tag = 1, mixed $remark = ''): void
{

    $log = new log();
    if (is_string($remark)) {
        $log::write($event, $id, $tag, $remark);
    } else {
        $log::write($event, $id, $tag, json_encode($remark));
    }
}

/** 将excel文件数据以ArrayBuffer格式返回
 * @param $excelData
 * @return Response
 */
function returnExcel($excelData): Response
{
    return Response::create($excelData, 'binary')
        ->header([
            'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8',
            'Content-Disposition' => 'attachment;filename="export.xlsx"',
            'Cache-Control' => 'max-age=0',
        ]);
}

/**
 * 把字符串中的非utf-8字符串清楚
 * @param $string
 * @return array|string|null
 */
function cleanUtf8($string): array|string|null
{
    return preg_replace('/[\x00-\x1F\x80-\x9F]/u', '', $string);
}

/**判定目标数据表是否存在
 * @param $tableName
 * @return bool
 */
function checkTableExists($tableName): bool
{
    // 查询数据库中的表信息
    $sql = "SHOW TABLES LIKE '{$tableName}'";
    $tableExists = Db::query($sql);
    // 检查结果
    if (!empty($tableExists)) {
        return true; // 表存在
    } else {
        return false; // 表不存在
    }
}

/**
 * 将指定表进行复制并重命名
 * @param $oldTableName
 * @param $newTableName
 * @param string $comment
 * @param bool $onlyStructure
 * @return bool
 */
function copyTable($oldTableName, $newTableName, string $comment = '', bool $onlyStructure = true): bool
{
    if (checkTableExists($newTableName)) {
        return true;
    }
    // 使用数据库的SQL语句复制表
    $sql = "CREATE TABLE {$newTableName} LIKE {$oldTableName};";

    // 执行创建表的SQL语句
    Db::execute($sql);

    // 如果需要复制数据，可以使用INSERT INTO ... SELECT语句
    if (!$onlyStructure) {
        $sqlInsert = "INSERT INTO {$newTableName} SELECT * FROM {$oldTableName};";
        Db::execute($sqlInsert);
    }
    // 如果备注不为空则为新创建的表新增备注
    if ($comment != '') {
        $sql = "ALTER TABLE `{$newTableName}` COMMENT = '{$comment}'";
        Db::execute($sql);
    }

    // 执行 SQL 语句
    return checkTableExists($newTableName);
}

/**将excel转为数组
 * @param $filePath
 * @return array
 */
function readExcelToArray($filePath)
{
    // 读取 Excel 文件
    $spreadsheet = IOFactory::load($filePath);

    // 获取所有工作表
    $sheetCount = $spreadsheet->getSheetCount();
    $data = [];
    for ($i = 0; $i < $sheetCount; $i++) {
        $sheet = $spreadsheet->getSheet($i);
        $rows = $sheet->toArray();

        // 将每个工作表的数据添加到数组中
        foreach ($rows as $rowIndex => $rowData) {
            // 如果整行都是null 则剔除
            if (empty(array_filter($rowData))) {
                continue;
            }
            $data[] = $rowData;
        }
    }

    return $data;


}

/**
 * @param array $data
 * @param String $needKey
 * @return array
 */
function convertValueToKey(array $data, string $needKey): array
{
    if (count($data) == 0) {
        return [];
    }
    $response = [];
    foreach ($data as $value) {
        $response[$value[$needKey]] = $value;
    }
    return $response;
}

/**
 * 将上传的文件存储到本地
 * @throws Exception
 */
function saveFile($file): string
{
    $fileTmpPath = $file['tmp_name'];
    $fileName = $file['name'];
    $fileSize = $file['size'];
    $fileError = $file['error'];

    // 你可以选择对文件名进行处理，以避免文件名冲突或安全问题
    $fileName = basename($fileName);
    $fileName = preg_replace("/[^a-zA-Z0-9._-]/", "", $fileName);

    // 指定文件保存的路径
    $uploadDir = public_path() . "uploads/excel/" . date('y-m-d', time()) . '/'; // 确保这个目录存在并且有写权限
    if (!is_dir($uploadDir)) {
        // 尝试创建目录
        if (!mkdir($uploadDir, 0777, true)) {
            // 如果创建目录失败，抛出错误
            throw new \Exception("无法创建目录：{$uploadDir}");
        }
    }
    $filePath = $uploadDir . $fileName;

    // 检查文件是否有错误
    if ($fileError === 0) {
        // 尝试移动文件到指定目录
        if (move_uploaded_file($fileTmpPath, $filePath)) {
            return $filePath;
        } else {
            throw new \Exception("文件上传失败", 8001);
        }
    } else {
        throw new \Exception("文件上传失败", 8002);
    }
}

/**把完整的省市区信息从字符串中取出来
 * @param $address
 * @return array
 */
#[ArrayShape(['province' => "mixed|null", 'city' => "mixed|null", 'district' => "mixed|null"])] function extractAddressComponents($address): array
{
    $pattern = "/(?P<province>[^省]+省|[^自治区]+自治区)?\s*(?P<city>[^市]+市|[^地区]+地区|[^自治州]+自治州)?\s*(?P<district>[^区]+区|[^县]+县|[^旗]+旗)?/u";
    preg_match($pattern, $address, $matches);

    return [
        'province' => $matches['province'] ?? null,
        'city' => $matches['city'] ?? null,
        'district' => $matches['district'] ?? null,
    ];
}